home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / forward.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  21.9 KB  |  828 lines

  1. /* Some of the code in this file was originally based on the following file:
  2.  * gateway.c : Paul Healy, EI9GL, 900818
  3.  *
  4.  * Rewrote forwarding mechanism to use "X-Forwarded-To" paradigm instead of
  5.  * "X-BBS-To", added timer support, etc.  Anders Klemets, SM0RGV, 901009.
  6.  */
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <ctype.h>
  10. #include <time.h>
  11. #include "global.h"
  12. #include "config.h"
  13. #include "bm.h"
  14. #include "mailbox.h"
  15. #include "cmdparse.h"
  16. #include "proc.h"
  17. #include "socket.h"
  18. #include "timer.h"
  19. #include "usock.h"
  20. #include "netuser.h"
  21. #include "ax25.h"
  22. #include "smtp.h"
  23. #include "netrom.h"
  24. #include "nr4.h"
  25. #include "files.h"
  26.  
  27. #define ISPROMPT(s)    (strlen(s) > 1 && s[strlen(s)-2] == '>')
  28. static struct timer fwdtimer;
  29.  
  30. extern char *RHdr;
  31.  
  32. static char *findident __ARGS((char *str, int n, char *result));
  33. static void sendmsg __ARGS((struct mbx *m,int msgn));
  34. char *mbxtime __ARGS((char *line));
  35. static int fwdinit __ARGS((struct mbx *m));
  36. static char *fwdanybbs __ARGS((struct mbx *m));
  37. static int timeok __ARGS((char *line));
  38. static void fwdtick __ARGS((void *v));
  39. static int isconnbbs __ARGS((struct mbx *m));
  40. static void startfwd __ARGS((int a,void *v1,void *v2));
  41. static int openconn __ARGS((int argc,char *argv[],void *p));
  42. static int sendmsgtobbs __ARGS((struct mbx *m, int msgn, int bulletin));
  43. static int makecl __ARGS((struct mbx *m, int msgn, char *line, char *subj, int bulletin));
  44. static char *grabtext __ARGS((char *from, char *to, int marker));
  45.  
  46. /***************************************************************************
  47.    findident copies the 'n'th alphanumeric sequence from 'str' to result.
  48.    It returns a ptr to result. It returns "\0" for missing identifier etc.
  49.    Uses isalnum macro to decide on alphanumeric/non-alnum status.
  50. */
  51. static char *findident(str, n, result)
  52. char *str, *result;
  53. int n;
  54. {
  55.    int count; /* current identifier */
  56.    count = 0;
  57.    *result = '\0';
  58.    while ( (count<n) && (*str!='\0') ) { /* Process alnum or non alnum seq */
  59.       while ( (*str!='\0') && (!isalnum(*str)) ) /* Get rid of ';:.@%"# etc */
  60.          str++;
  61.       if ( (str!='\0') && isalnum(*str) ) { /* this is an alnum seq */
  62.          count++;
  63.          while ( (*str!='\0') && (isalnum(*str) || (*str=='_')) )
  64.             if (count==n)
  65.                *result++ = *str++;
  66.             else str++;
  67.          if (count==n)
  68.             *result = '\0';
  69.          }
  70.       }
  71.    return result;
  72. }
  73. /**************************************************************************/
  74. static void
  75. sendmsg(m,msgn)
  76. struct mbx *m;
  77. int msgn;
  78. {
  79.     char buf[LINELEN], tb[LINELEN], *cp;
  80.     int len, rec = 0;
  81.     long cnt;
  82.     fseek(m->mfile,m->mbox[msgn].start,0);
  83.     cnt = m->mbox[msgn].size;
  84.  
  85.     /* If the data part of the message starts with "R:" the RFC-822
  86.      * headers will not be forwarded. Instead we will add an R:
  87.      * line of our own.
  88.      */
  89.     for(;;) {
  90.         if(fgets(buf,sizeof(buf),m->mfile) == NULLCHAR)
  91.             break;
  92.         cnt -= strlen(buf);
  93.         if(rec == 1) {    /* look at the line following Received: */
  94.              ++rec;
  95.              if((cp = strchr(buf,';')) != NULLCHAR){
  96.               strcpy(tb,cp+1);     /* get the date of receipt */
  97.               ++rec;
  98.              }
  99.         }
  100.         /* The first Received: line is the one that we have added */
  101.         if(!rec && htype(buf) == RECEIVED)
  102.              ++rec;
  103.         if(*buf == '\n') {
  104.              if(rec == 3 && cnt > 1) {
  105.               fread(buf,1,2,m->mfile);
  106.               cnt -= 2;
  107.               if(strncmp(buf,"R:",2) == 0) {
  108.                    pax25(buf,Mycall);
  109.                    if((cp = strchr(buf,'-')) != NULLCHAR)
  110.                     *cp = '\0';    /* remove SSID */
  111.                                usprintf(m->user,
  112.                                      "R:%s @:%s %s [AmigaNOS %s]\nR:",
  113.                                      mbxtime(tb), buf, Hostname, Version);
  114.                    break;
  115.               }
  116.              }
  117.              /* Start over, forwarding the RFC-822 headers */
  118.              fseek(m->mfile,m->mbox[msgn].start,0);
  119.              cnt = m->mbox[msgn].size;
  120.              rec = 0;
  121.              break;
  122.         }
  123.        }
  124.     while(rec != 3) {    /* Forward the RFC-822 headers */
  125.         if(fgets(buf,sizeof(buf),m->mfile) == NULLCHAR)
  126.             break;
  127.         cnt -= strlen(buf);
  128.         switch(htype(buf)) {
  129.         case XFORWARD: /* Do not forward the "X-Forwarded-To:" lines */
  130.         case STATUS:   /* Don't forward the "Status:" line either */
  131.              break;
  132.         default:
  133.              usputs(m->user,buf);
  134.         }
  135.         if(*buf == '\n')    /* last header line */
  136.             break;
  137.     }
  138.     do {    /* the rest of the message is treated below */
  139.         len = min(cnt,sizeof(buf)-1);
  140.         if(fread(buf,1,len,m->mfile) != len)
  141.             break;
  142.         cnt -= len;
  143.         buf[len] = '\0';
  144.         usputs(m->user,buf);
  145.     } while(cnt);
  146. }
  147.  
  148. /* Parse a line for date and time in Arpanet format
  149.  * (Day, day Month year hh:mm:ss Zone) and return it in mailbox format
  150.  * (yymmdd/hhmmz)
  151.  */
  152. char *
  153. mbxtime(line)
  154. char *line;
  155. {
  156.      extern char *Months[];
  157.      static char buf[13]; /* was [12] */
  158.      char *cp;
  159.      int i, day;
  160.      cp = line;
  161.      while(isspace(*cp))    /* skip initial blanks */
  162.       ++cp;
  163.      if(*cp == '\0')
  164.       return NULLCHAR;
  165.      if(strlen(cp) < 22)
  166.       return NULLCHAR;
  167.      cp += 5;
  168.      day = atoi(cp);
  169.      if(*(++cp) != ' ')
  170.       ++cp;
  171.      ++cp;
  172.      for(i=0; i < 12; ++i)
  173.       if(strnicmp(Months[i],cp,3) == 0)
  174.            break;
  175.      if(i == 12)
  176.       return NULLCHAR;
  177.      sprintf(buf,"%02d%02d%02d/%02d%02d%c",atoi(cp + 4),i+1,day,atoi(cp + 7),
  178.          atoi(cp + 10), strnicmp(cp + 16,"GMT",3) ? ' ' : 'z');
  179.      return buf;
  180. }
  181.      
  182. static char *
  183. grabtext(from, to, marker)
  184. char *from, *to;
  185. int marker;
  186. {
  187.    while (*from!=marker)
  188.       *to++ = *from++;
  189.    *to = '\0';
  190.    return from+1;
  191. }
  192.  
  193. /* Makes a command line and returns -1 if the message cannot be sent. */
  194. static int
  195. makecl(m, msgn, line, subj, bulletin)
  196. struct mbx *m;
  197. int msgn;        /* Message number */
  198. char *line, *subj;    /* Buffers to keep command line and subject */
  199. int bulletin;        /* True if message is in public message area */
  200. {
  201.    char bid[LINELEN], to[LINELEN], atbbs[LINELEN], from[LINELEN],
  202.     buf[LINELEN], *cp;
  203.    if(m->mfile == NULLFILE)
  204.     return -1;
  205.    if(!bulletin && (m->mbox[msgn].status & BM_READ))
  206.     return -1;    /* the message was already read */
  207.    fseek(m->mfile,m->mbox[msgn].start,0);
  208.    *bid = *to = *atbbs = *from = '\0';
  209.    if(subj != NULLCHAR)
  210.     *subj = '\0';
  211.    m->stype = bulletin ? 'B' : 'P';    /* default to SB or SP */
  212.    while (fgets(buf,sizeof(buf),m->mfile)) {
  213.       if (buf[0] == '\n')
  214.          break; /* envelope finished */
  215.       switch (htype(buf)) {
  216.       case TO:
  217.         /* The following code tries to parse "To: " lines where the
  218.          * address looks like any of the following: "to@atbbs",
  219.          * "<to@atbbs>", "<to%atbbs@host>" and with possible spaces
  220.          * surrounding the '<>' characters.
  221.          */
  222.         if((cp = getaddress(buf,0)) == NULLCHAR)
  223.         break;
  224.         rip(buf);
  225.         strcpy(to,cp);
  226.         if((cp = strchr(to,'%')) != NULLCHAR) { /* look for a '%' */
  227.          strcpy(atbbs,cp + 1);
  228.          *cp = '\0';    /* "to" ends at the '%' character */
  229.         }
  230.         else {    /* no '%' but maybe a '@'? */
  231.          if((cp = strchr(to,'@')) != NULLCHAR) {
  232.               strcpy(atbbs,cp + 1);
  233.               *cp = '\0';    /* "to" ends at the '@' character */
  234.          }
  235.         }
  236.         if(*atbbs != '\0')        /* either '%' or '@' found */
  237.          /* cut "atbbs" at the first '@' character */
  238.          for(cp = atbbs; *cp != '\0'; ++cp)
  239.               if(*cp == '@') {
  240.                *cp = '\0';
  241.                break;
  242.               }
  243.         /* "to" or "atbbs" should not be more than 6 characters (ALEN).
  244.          * If "to" is too long, it might simply be because the area name
  245.          * is longer than 6 characters, but it might also be because
  246.          * the address on the To: line is in an obscure format that we
  247.          * failed to parse (eg '!' character notation.)
  248.          */
  249.         if(strlen(to) > ALEN) {
  250.         /* Play safe and set "to" and "atbbs" to the area name */
  251.         strcpy(to,m->area);
  252.         strcpy(atbbs,m->area);
  253.               }
  254.         if(*atbbs == '\0')
  255.         strcpy(atbbs,to);
  256.               to[ALEN] = '\0';
  257.         /* Only if the BBS supports "hierarchical routing designators"
  258.          * is the atbbs field allowd to be longer than 6 characters and
  259.          * have dots in it.
  260.          */
  261.         if((m->sid & MBX_HIER_SID) == 0) {
  262.          atbbs[ALEN] = '\0';    /* 6 character limit */
  263.          if((cp = strchr(atbbs,'.')) != NULLCHAR)
  264.               *cp = '\0';    /* cut "atbbs" at first dot */
  265.         }
  266.             break;
  267.       case MSGID:
  268.         /* The following code distinguishes between two different types
  269.          * of Message-IDs: <abcde@callsign.bbs> and <abcde@host.domain>.
  270.          * The first type is converted to $abcde and the second to
  271.          * $abcde_host.domain. This preserves compability with BBSes.
  272.          */
  273.         if((cp = getname(buf)) == NULLCHAR)
  274.          break;
  275.         bid[0] = '$';
  276.         strcpy(&bid[1],cp);
  277.               cp = strchr(bid,'@');
  278.         /* A trailing ".bbs" indicates that the Message-ID was generated
  279.          * from a BBS style message, and not a RFC-822 message.
  280.          */
  281.         if(cp != NULLCHAR && stricmp(&bid[strlen(bid) - 4], ".bbs") == 0)
  282.         *cp = '\0';
  283.         else
  284.         *cp = '_';
  285.         bid[13] = '\0';    /* BIDs should be no longer than 12 bytes */
  286.               break;
  287.       case SUBJECT:
  288.         if(subj != NULLCHAR)
  289.               (void) grabtext(buf+9, subj, '\n');
  290.             break;
  291.       case FROM:
  292.         if((cp = getaddress(buf,0)) != NULLCHAR) {
  293.         if(strstr(cp,m->name) != NULLCHAR) {
  294.            /* This message came from the connected bbs, abort */
  295.            return -1;
  296.         }
  297.         findident(cp, 1, from);        /* cp points to from@domain */
  298.         from[ALEN] = '\0';    /* 6 character limit */
  299.        }
  300.             break;
  301.       case XFORWARD:
  302.         rip(buf);
  303.         if((cp = getaddress(buf,0)) == NULLCHAR)
  304.          break;
  305.         if(stricmp(m->name,cp) == 0)
  306.         /* This message has already been forwarded, abort */
  307.         return -1;
  308.         break;
  309.       case BBSTYPE:
  310.         m->stype = buf[16];
  311.         break;
  312.       default:
  313.         break;
  314.       }
  315.    }
  316.    /* Check for an invalid RFC-822 header */
  317.    if(to[0] == '\0' || from[0] == '\0')
  318.     return -1;
  319.  
  320.    if(line != NULLCHAR)
  321.     sprintf(line, "S%c %s @ %s < %s %s\n", m->stype, to, atbbs, from,
  322.         (m->sid & MBX_SID) ? bid : "");
  323. /*        (bulletin & (m->sid & MBX_SID)) ? bid : ""); */
  324.    return 0;
  325. }
  326.  
  327. static int /* 0 = ok, -1 = problem so disc */
  328. sendmsgtobbs(m, msgn, bulletin)
  329. struct mbx *m;
  330. int msgn, bulletin;
  331. {
  332.    int result = -1;
  333.    char line[64], subj[256], input[MBXLINE];
  334.    if(makecl(m, msgn, line, subj, bulletin) == -1)
  335.     return 0;    /* do not forward this particular message */
  336.    tputs(line);         /* Send mail offer to bbs */
  337.    rip(line);
  338.    usflush(m->user);
  339.    if (recvline (m->user, input, sizeof(input)) != -1 ) {
  340.       if (input[0] == 'O' || input[0] == 'o' || (m->sid & MBX_SID) == 0) {
  341.      /* Got 'OK' or any line if the bbs is unsofisticated */
  342.          tprintf("%s\n", subj);
  343.      sendmsg(m,msgn);    /* send the message */
  344.          tputs("/EX\n"); /* was 0x1a */
  345.          usflush(m->user);
  346.            /* get F> for a good deliver */
  347.            while (recvline (m->user, input, sizeof(input)) != -1 )
  348.         if (ISPROMPT(input)) {
  349.             mainlog(m->user,"MBOX bbs mail sent: %s ", line);
  350.             if(bulletin)
  351.                 m->mbox[msgn].status |= BM_FORWARDED;
  352.             else
  353.                 m->mbox[msgn].status |= BM_DELETE;
  354.             m->change = 1;
  355.             result = 0;
  356.             break;
  357.         }
  358.       }
  359.       else { /* OK response not received from bbs */
  360.           if (input[0] == 'N' || input[0] == 'n') {    /* 'NO' respone */
  361.               mainlog(m->user,"MBOX bbs mail refused: %s ", line);
  362.         if(bulletin)
  363.             m->mbox[msgn].status |= BM_FORWARDED;
  364.         else
  365.             /* Mail should already be there */
  366.             m->mbox[msgn].status |= BM_DELETE;
  367.         m->change = 1;
  368.           }
  369.             /* should get a F> here */
  370.           while (recvline (m->user, input, sizeof(input)) != -1 )
  371.               if (ISPROMPT(input)) {
  372.                   result = 0;
  373.             break;
  374.               }
  375.       }
  376.    } /* OK or NO here */
  377.    return result;
  378. }
  379.  
  380. /* This is the main entry point for reverse forwarding. It is also used
  381.  * for normal, "forward", forwarding.
  382.  */
  383. int
  384. dorevfwd(argc,argv,p)
  385. int argc;
  386. char *argv[];
  387. void *p;
  388. {
  389.     char oldarea[64], line[MBXLINE], *cp;
  390.     struct mbx *m;
  391.     int i, bulletin, err = 0;
  392.     m = (struct mbx *)p;
  393.     mainlog(m->user,"MBOX forwarding mail to: %s ", m->name);
  394.     /* indicate we are doing reverse forwarding, if we are not already
  395.      * doing normal forwarding.
  396.      */
  397.     if(m->state != MBX_FORWARD)
  398.         m->state = MBX_REVFWD;
  399.     if(fwdinit(m) != -1) {
  400.         strcpy(oldarea,m->area);
  401.         while(!err && fgets(line,sizeof(line),m->tfile) != NULLCHAR) {
  402.             if(*line == '-')    /* end of record reached */
  403.                 break;
  404.             cp = strchr(line,' ');    /* remove trailing blanks */
  405.             if(cp != NULLCHAR)
  406.                 *cp = '\0';
  407.             if((cp = strchr(line,'\t')) != NULLCHAR)
  408.                 *cp = '\0';
  409.             if(*line == '\0' || *line == '.')
  410.                 continue;
  411.             rip(line);
  412.             changearea(m,line);
  413.             bulletin = isarea(line);    /* public area */
  414.             for(i=1; i<=m->nmsgs; i++)
  415.                 if(sendmsgtobbs(m, i, bulletin) == -1) {
  416.                     err = 1;    /* abort */
  417.                     break;
  418.                 }
  419.         }
  420.         fclose(m->tfile);
  421.         m->tfile = NULLFILE;
  422.         if(*oldarea != '\0') 
  423.             changearea(m,oldarea);
  424.     }
  425.     if(m->state == MBX_FORWARD) {
  426.         return 0;
  427.     }
  428.     tprintf("*** Done\n");
  429.     if((m->sid & MBX_RLI_SID))    /* disconnect if it is a W0RLI bbs */
  430.         domboxbye(0,NULL,m);
  431.     return 0;
  432. }
  433.  
  434. /* Read the forward file for a record for the connected BBS. If found,
  435.  * return 1 if this is the right time to forward, m->tfile is left pointing
  436.  * at the first message area to be forwarded.
  437.  */
  438. static int
  439. fwdinit(m)
  440. struct mbx *m;
  441. {
  442.     char line[MBXLINE], host[80];
  443.     int start = 1;
  444.     if((m->tfile = fopen(Forwardfile,READ_TEXT)) == NULLFILE)
  445.         return -1;
  446.     while(fgets(line,sizeof(line),m->tfile) != NULLCHAR) {
  447.         if(*line == '\n')
  448.             continue;
  449.         /* lines starting with '-' separate the forwarding records */
  450.         if(*line == '-') {
  451.             start = 1;
  452.             continue;
  453.         }
  454.         if(start) {
  455.             start = 0;
  456.             /* get the name of this forwarding record */
  457.             findident(line,1,host);
  458.             if(stricmp(m->name,host) == 0) {
  459.                 if(!timeok(line))
  460.                     break;
  461.                 /* eat the connect command line */
  462.                 fgets(line,sizeof(line),m->tfile);
  463.                 return 0;
  464.             }
  465.         }
  466.     }
  467.     fclose(m->tfile);
  468.     m->tfile = NULLFILE;
  469.     return -1;
  470. }
  471. /* Read the forward file for a record for the connected BBS. If found,
  472.  * determine if this is the right time to forward, and return the command
  473.  * line to establish a forwarding connection. m->tfile is left pointing
  474.  * at the first message area to be forwarded.
  475.  */
  476. static char *
  477. fwdanybbs(m)
  478. struct mbx *m;
  479. {
  480.     char line[MBXLINE], host[80];
  481.     int start = 1;
  482.     if(m->tfile == NULLFILE && (m->tfile = fopen(Forwardfile,READ_TEXT))
  483.                     == NULLFILE)
  484.         return NULLCHAR;
  485.     while(fgets(line,sizeof(line),m->tfile) != NULLCHAR) {
  486.         if(*line == '\n')
  487.             continue;
  488.         /* lines starting with '-' separate the forwarding records */
  489.         if(*line == '-') {
  490.             start = 1;
  491.             continue;
  492.         }
  493.         if(start) {
  494.             start = 0;
  495.             /* get the name of this forwarding record */
  496.             findident(line,1,host);
  497.             strcpy(m->name,host);
  498.             if(!timeok(line))
  499.                 continue;    /* too late or too early */
  500.             /* get the connect command line */
  501.             fgets(line,sizeof(line),m->tfile);
  502.             return strdup(line);
  503.         }
  504.     }
  505.     fclose(m->tfile);
  506.     m->tfile = NULLFILE;
  507.     return NULLCHAR;
  508. }
  509.  
  510. /* get any groups of four digits that specify the begin and ending hours of
  511.  * forwarding. Returns 1 if forwarding may take place.
  512.  */
  513. static int
  514. timeok(line)
  515. char *line;
  516. {
  517.     char hours[80], *now;
  518.     long t;
  519.     int t1, t2, pos = 2;
  520.     findident(line,pos++,hours);
  521.     if(*hours == '\0')
  522.         return 1;    /* no digits default to 0023, ie. anytime */
  523.     time(&t);
  524.     now = ctime(&t) + 11;
  525.     *(now + 2) = '\0';
  526.     while(*hours != '\0') {
  527.         t1 = (*hours - '0') * 10 + (*(hours+1) - '0');
  528.         t2 = (*(hours+2) - '0') * 10 + (*(hours+3) - '0');
  529.         if(atoi(now) >= t1 && atoi(now) <= t2)
  530.             return 1;        /* right in time */
  531.         findident(line,pos++,hours);    /* get next group if any */
  532.     }
  533.     return 0;    /* too early or too late */
  534. }
  535.  
  536. int
  537. dombtimer(argc,argv,p)
  538. int argc;
  539. char *argv[];
  540. void *p;
  541. {
  542.     if(argc < 2){
  543.         tprintf("Forwarding timer: %lu/%lu\n",
  544.         read_timer(&fwdtimer) * MSPTICK/1000,
  545.         dur_timer(&fwdtimer) * MSPTICK/1000);
  546.         return 0;
  547.     }
  548.     fwdtimer.func = (void (*)())fwdtick;/* what to call on timeout */
  549.     fwdtimer.arg = NULL;        /* dummy value */
  550.     set_timer(&fwdtimer,atol(argv[1])*1000); /* set timer duration */
  551.     start_timer(&fwdtimer);        /* and fire it up */
  552.     return 0;
  553. }
  554.  
  555. int
  556. dombkick(argc,argv,p)
  557. int argc;
  558. char *argv[];
  559. void *p;
  560. {
  561.     fwdtick(NULL);
  562.     return 0;
  563. }
  564.  
  565. /* called when the forward timer expires or explicitly by dombkick() */
  566. static void
  567. fwdtick(v)
  568. void *v;
  569. {
  570.     char line[MBXLINE], *cc, *cp;
  571.     struct mbx *m;
  572.     int i, bulletin, skip = 0;
  573.     /* restart the timer */
  574.     start_timer(&fwdtimer);
  575.     if((m = newmbx()) == NULLMBX)
  576.         return;
  577.     m->user = Curproc->output;
  578.     m->state = MBX_TRYING;
  579.     while((cc = fwdanybbs(m)) != NULLCHAR) {
  580.         if(isconnbbs(m)) /* already connected to this BBS, skip it */
  581.             skip = 1;
  582.         while(fgets(line,sizeof(line),m->tfile) != NULLCHAR) {
  583.             if(*line == '-') {    /* end of record reached */
  584.                 skip = 0;
  585.                 break;
  586.             }
  587.             cp = strchr(line,' ');    /* remove trailing blanks */
  588.             if(cp != NULLCHAR)
  589.                 *cp = '\0';
  590.             if((cp = strchr(line,'\t')) != NULLCHAR)
  591.                 *cp = '\0';
  592.             if(skip || *line == '\0' || *line == '.')
  593.                 continue;
  594.             rip(line);
  595.             changearea(m,line);
  596.             bulletin = isarea(line);    /* public area */
  597.             /* check if there are any messages in this area
  598.              * that need to be forwarded.
  599.              */
  600.             for(i=1; i<=m->nmsgs; i++)
  601.                 if(makecl(m, i, NULLCHAR, NULLCHAR, bulletin)
  602.                     == 0) {
  603.                     newproc("Mbox forwarding", 2048,
  604.                         startfwd, 0, (void *)cc,
  605.                         (void *)strdup(m->name));
  606.                     skip = 1;
  607.                     cc = NULLCHAR;
  608.                     break;
  609.                 }
  610.         }
  611.         free(cc);
  612.     }
  613.     exitbbs(m);
  614. }
  615.  
  616. /* returns 1 if m->name matches the name of another connected mailbox. */
  617. static int
  618. isconnbbs(m)
  619. struct mbx *m;
  620. {
  621.     int i;
  622.     for(i = 0; i < NUMMBX; ++i)
  623.         if(Mbox[i] != NULLMBX && Mbox[i] != m &&
  624.             stricmp(m->name,Mbox[i]->name) == 0)
  625.                 return 1;
  626.     return 0;
  627. }
  628.  
  629. /* possible commands on the command line in the forwarding file */
  630. static struct cmds cfwdcmds[] = {
  631.     "tcp",        openconn,    0, 0, NULLCHAR,
  632.     "telnet",    openconn,    0, 0, NULLCHAR,
  633. #ifdef AX25
  634.     "ax25",        openconn,    0, 0, NULLCHAR,
  635.     "connect",    openconn,    0, 0, NULLCHAR,
  636. #endif
  637. #ifdef NETROM
  638.     "netrom",    openconn,    0, 0, NULLCHAR,
  639. #endif
  640.     NULLCHAR
  641. };
  642.  
  643. /* this function is called whenever the forwarding timer expires */
  644. static void
  645. startfwd(a,v1,v2)
  646. int a;
  647. void *v1, *v2;
  648. {
  649.     struct mbx *m;
  650.     char *cc;
  651.     cc = (char *) v1;
  652.     if((m = newmbx()) == NULLMBX) {
  653.         free(cc);
  654.         return;
  655.     }
  656.     strcpy(m->name,(char *)v2);
  657.     free((char *)v2);
  658.     m->state = MBX_TRYING;
  659.     /* open the connection, m->user will be the new socket */
  660.     if(cmdparse(cfwdcmds,cc,(void *)m) == -1) {
  661.         free(cc);
  662.         exitbbs(m);
  663.         return;
  664.     }
  665.     free(cc);
  666.     m->state = MBX_FORWARD;
  667.     sockowner(m->user,Curproc);
  668.     close_s(Curproc->output);
  669.     close_s(Curproc->input);
  670.     /* m->user will be closed automatically when this process exits */
  671.     Curproc->output = Curproc->input = m->user;
  672.     /* We'll do our own flushing right before we read input */
  673.     setflush(m->user,-1);
  674.  
  675.     if(fwdinit(m) == -1) {
  676.         /* it is probably not the right time to forward anymore */
  677.         exitbbs(m);
  678.         return;
  679.     }
  680.     /* read the connect script. Lines starting with a dot will be sent
  681.      * to the remote BBS.
  682.      */
  683.     while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR)
  684.         if(*m->line == '.')
  685.             tputs(m->line + 1);
  686.         else
  687.             break;
  688.     usflush(m->user);
  689.     fclose(m->tfile);
  690.     m->tfile = NULLFILE;
  691.  
  692.     /* read the initial output from the bbs, looking for the SID */
  693.     for(;;) {
  694.         if(recvline(m->user,m->line,MBXLINE) == -1) {
  695.             exitbbs(m);
  696.             return;
  697.         }
  698.         if(ISPROMPT(m->line))
  699.             break;
  700.         if(*m->line == '[') {        /* parse the SID */
  701.             rip(m->line);
  702.             mbx_parse(m);
  703.             continue;
  704.         }
  705.     }
  706.     /* Now sync the two ends as telnet password messes them up */
  707.     if(socklen(m->user,0))        /* discard any remaining input */
  708.         recv_mbuf(m->user,NULL,0,NULLCHAR,0);
  709.  
  710.     /* send our SID if the peer announced its SID */
  711.     if(m->sid & MBX_SID) {
  712.         tprintf("%s\n",Mversion);
  713.         usflush(m->user);
  714.         for(;;) {
  715.             if(recvline(m->user,m->line,MBXLINE) == -1) {
  716.                 exitbbs(m);
  717.                 return;
  718.             }
  719.             if(ISPROMPT(m->line))
  720.                 break;
  721.         }
  722.     }
  723.     /* start the actual forwarding */
  724.     dorevfwd(0,NULL,(void *)m);
  725.     /* ask for reverse forwarding or just disconnect */
  726.     if(((m->sid & MBX_SID) && tputs("F>\n") == -1) ||
  727.        (m->sid & MBX_SID) == 0) {
  728.         exitbbs(m);
  729.         return;
  730.     }
  731.     usflush(m->user);
  732.     /* parse the commands that are are received during reverse
  733.      * forwarding.
  734.      */
  735.     while(recvline(m->user,m->line,MBXLINE) > 0) {
  736.         rip(m->line);
  737.         if(mbx_parse(m) == 2)    /* got the "*** Done" command */
  738.             break;
  739.         tputs("F>\n");
  740.         usflush(m->user);
  741.     }
  742.     exitbbs(m);
  743. }
  744.  
  745. /* open a network connection based upon information in the cc line.
  746.  * m->user is set to the socket number.
  747.  */
  748. static int
  749. openconn(argc,argv,p)
  750. int argc;
  751. char *argv[];
  752. void *p;
  753. {
  754.     struct mbx *m;
  755.     char sock[MAXSOCKSIZE], *np, alias[AXBUF];
  756.     union sp sp;
  757.     int len;
  758.     m = (struct mbx *)p;
  759.     sp.p = sock;
  760.     if(argc < 2)
  761.         return -1;
  762.     switch(*argv[0]) {
  763.     case 't':
  764.         sp.in->sin_family = AF_INET;
  765.         if((sp.in->sin_addr.s_addr = resolve(argv[1])) == 0)
  766.             return -1;
  767.         /* get the optional port number */
  768.         if(argc > 2)
  769.             sp.in->sin_port = atoi(argv[2]);
  770.         else
  771.             sp.in->sin_port = IPPORT_TELNET;
  772.         if((m->user = socket(AF_INET,SOCK_STREAM,0)) == -1)
  773.             return -1;
  774.         len = sizeof(*sp.in);
  775.         break;
  776. #ifdef AX25
  777.     case 'a':
  778.     case 'c':    /* allow 'c' for 'connect' as well */
  779.         if(argc < 3)
  780.             return -1;
  781.         sp.ax->sax_family = AF_AX25;
  782.         strncpy(sp.ax->iface,argv[1],ILEN); /* the interface name */
  783.         setcall(sp.ax->ax25_addr,argv[2]); /* the remote callsign */
  784.         /* no digipeaters for now, use the "ax25 route add" command */
  785.         if((m->user = socket(AF_AX25,SOCK_STREAM,0)) == -1)
  786.             return -1;
  787.         len = sizeof(*sp.ax);
  788.         break;
  789. #endif /* AX25 */
  790. #ifdef NETROM
  791.     case 'n':
  792.         sp.nr->nr_family = AF_NETROM;
  793.         len = sizeof(*sp.nr);
  794.         if((m->user = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1)
  795.             return -1;
  796.         memcpy(sp.nr->nr_addr.user,Nr4user,AXALEN);
  797.         memcpy(sp.nr->nr_addr.node,Mycall,AXALEN);
  798.         bind(m->user,sp.p,len);
  799.         /* See if the requested destination could be an alias, and
  800.          * use it if it is.  Otherwise assume it is an AX.25
  801.          * address.
  802.          */
  803.         if (putalias(alias,argv[1],0) != -1 &&
  804.             (np = find_nralias(alias)) != NULLCHAR) {
  805.                 memcpy(sp.nr->nr_addr.user,np,AXALEN) ;
  806.                 memcpy(sp.nr->nr_addr.node,np,AXALEN) ;
  807.         }
  808.         else {    /* parse ax25 callsign */
  809.         /* Only the user callsign of the remote station is never
  810.          * used by NET/ROM, but it is needed for the psocket() call.
  811.          */
  812.             setcall(sp.nr->nr_addr.user,argv[1]);
  813.             setcall(sp.nr->nr_addr.node,argv[1]);
  814.         }
  815.         break;
  816. #endif /* NETROM */
  817.     default:
  818.         return -1;
  819.     }
  820.     if(connect(m->user,sp.p,len) == -1) {
  821.         mainlog(m->user,"MBOX forward failed: %s errno %d",
  822.                 sockerr(m->user),errno);
  823.         close_s(m->user);
  824.         return -1;
  825.     }
  826.     return m->user;
  827. }
  828.